<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 调度执行
        let data = {
            foo: 1,
            bar: 'bar'
        }
        let activeEffect;
        let effectStack = []
        function effect (fn, options) {
            const effectFn = () => {
                cleanup(effectFn)
                activeEffect = effectFn
                effectStack.push(effectFn)
                fn()
                effectStack.pop()
                activeEffect = effectStack[effectStack.length - 1]
            }
            // 把options挂载到effectFn上
            effectFn.options = options
            effectFn.deps = []
            effectFn()
        } 
        function cleanup (effectFn) {
            for (let i = 0; i < effectFn.deps.length; i++) {
                const deps = effectFn.deps[i]
                deps.delete(effectFn)
            }
            effectFn.deps.length = 0
        }
        const bucket = new WeakMap()
        const obj = new Proxy(data, {
            get(target, key) {
                track(target, key)
                return target[key]
            },
            set(target, key, newVal) {
                target[key] = newVal
                trigger(target, key)
            }
        })

        // 定义一个任务队列
        const jobQuene = new Set()
        // 使用Promise.resolve()创建一个promise实例，借助他，将一个任务添加到微任务队列
        const p = Promise.resolve()

        // 标志，是否正在刷新队列
        let isFlushing = false
        // 刷新函数
        function flushJob () {
            // 如果队列正在刷新，则什么都不做
            if (isFlushing) return
            // 设置为true，代表正在刷新
            isFlushing = true
            // 在微任务队列中刷新jobQuene队列
            p.then(() => {
                jobQuene.forEach(job => job())
            }).finally(() => {
                isFlushing = false
            })
        }

        let temp1, temp2;
        // // 
        // effect(() => {
        //     console.log(obj.foo, 'obj.foo');
        // })
        // obj.foo++
        // console.log('结束了');
        effect(
            () => {
                console.log(obj.foo, 'obj.foo');
            }
        )
        obj.foo++
        obj.foo++
        

        function track (target, key) {
            if (!activeEffect) return
            let depsMap = bucket.get(target)
            if (!depsMap) {
                bucket.set(target, (depsMap = new Map()))
            }
            let deps = depsMap.get(key)
            if (!deps) {
                depsMap.set(key, (deps = new Set()))
            }
            deps.add(activeEffect)
            activeEffect.deps.push(deps)
        }

        function trigger (target, key) {
            let depsMap = bucket.get(target)
            if (!depsMap) return 
            let effects = depsMap.get(key)
            const effectsToRun = new Set(effects)
            effectsToRun && effectsToRun.forEach(effectFn => {
                if (effectFn.options.scheduler) {
                    effectFn.options.scheduler(effectFn)
                } else {
                    effectFn()
                }
            })
        }
    </script>
</body>
</html>